﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PloobsEngine.SceneControl;
using PloobsEngine.Physics;
using PloobsEngine.Modelo;
using PloobsEngine.Material;
using PloobsEngine.Engine;
using PloobsEngine.Light;
using PloobsEngine.Physics.Bepu;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using PloobsEngine.Cameras;
using PloobsEngine.Input;
using PloobsEngine.Entity;
using PloobsEngine.MessageSystem;
using PloobsEngine.Physic.PhysicObjects.BepuObject;
using BEPUphysics.UpdateableSystems.ForceFields;
using PloobsEngine.Features;
using PloobsEngine.Commands;

namespace PloobsProjectTemplate.Screens
{
    class InsideDeathStar : IScene
    {
    
        Camera camFollowObject;

        CameraStatic cam;

        IModelo mXWing;

        SphereObject poXWing;

        XWing xWing;

        Maze maze;

        BasicEffect basicEffect;

        float gameSpeed = 5f;

        float moveSpeed;

        float turningSpeed;

        Vector3 pos;

        City city;

        GraphicsDevice device;

        
        protected override void SetWorldAndRenderTechnich(out IRenderTechnic renderTech, out IWorld world)
        {
            world = new IWorld(new BepuPhysicWorld(0f, true, 1), new SimpleCuller());


            ///Create the deferred technich
            DeferredRenderTechnicInitDescription desc = DeferredRenderTechnicInitDescription.Default();
            desc.DefferedDebug = false;
            desc.UseFloatingBufferForLightMap = false;
            renderTech = new DeferredRenderTechnic(desc);
        }
        protected override void LoadContent(GraphicInfo GraphicInfo, GraphicFactory factory, IContentManager contentManager)
        {
            base.LoadContent(GraphicInfo, factory, contentManager);

            //#region "Floor"
            //Texture2D floor = factory.GetTexture2D("textura")
            //LoadFloorPlan();
            //#endregion

            #region "XWing Model"

            mXWing = new SimpleModel(factory, "XWing");

            poXWing = new SphereObject(new Vector3(0, 0, -100), mXWing.GetModelRadius(), 10f, 0.5f, MaterialDescription.DefaultBepuMaterial());
            
            poXWing.Entity.CollisionInformation.Events.InitialCollisionDetected +=
                new BEPUphysics.Collidables.Events.InitialCollisionDetectedEventHandler<BEPUphysics.Collidables.MobileCollidables.EntityCollidable>(Colidiu);

            IShader shXWing = new ForwardXNABasicShader(new ForwardXNABasicShaderDescription(Color.Red, Color.Red, Color.Red));

            IMaterial matXWing = new DeferredMaterial(shXWing);

            xWing = new XWing(poXWing, matXWing, mXWing);

            this.World.AddObject(xWing);

            #endregion

            #region "Camera"
            
            cam = new CameraStatic(Vector3.Zero, new Vector3(0,0,-10));

            camFollowObject = new Camera(xWing, Vector3.Forward);
            
            this.World.CameraManager.AddCamera(camFollowObject);

            this.World.CameraManager.AddCamera(cam);
                        
            this.World.CameraManager.SetActiveCamera(camFollowObject.Name);
            //this.World.CameraManager.SetActiveCamera(cam.Name);

            #endregion

            #region "Maze"

            basicEffect = new BasicEffect(device);
            
            maze = new Maze(device);

            //city = new City(cam, device);

            city = new City(device);

            city.LoadContent(factory);
            
            #endregion

            #region "SKY"

            //IModelo sky = new SimpleModel(factory, "SKY//skysphere_mesh");
            //TriangleMeshObject poSky = new TriangleMeshObject(sky, Vector3.Zero);
            //IObject objSky = new IObject(matXWing, sky, poSky);
            
            //SkyPostEffects skyPostEffect = new SkyPostEffects();
            //skyPostEffect.list.Add(objSky);
            
            SkyBoxSetTextureCube stc = new SkyBoxSetTextureCube("SKY//Black_sky");
            CommandProcessor.getCommandProcessor().SendCommandAssyncronous(stc);
            #endregion

            //this.RenderTechnic.AddPostEffect(new AntiAliasingPostEffectStalker());
        }

        protected override void InitScreen(GraphicInfo GraphicInfo, EngineStuff engine)
        {
            base.InitScreen(GraphicInfo, engine);
            device = engine.GraphicsDevice;
            SkyBox skybox = new SkyBox();
            engine.AddComponent(skybox);

        }

        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            ProcessKeyboard(gameTime);

            moveSpeed = gameTime.ElapsedGameTime.Milliseconds / 500.0f * 5f * gameSpeed;

            turningSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f * gameSpeed;


            MoveForward(ref pos, xWing.xWingRotation, moveSpeed);

            pos = xWing.PhysicObject.Position;
        }

        protected override void Draw(GameTime gameTime, RenderHelper render)
        {
            base.Draw(gameTime, render);

            //maze.Draw(cam , basicEffect);

            //maze.Draw(render, basicEffect);

            //city.DrawCity(GraphicFactory.GetTexture2D("texturemap"));

            
            xWing.PhysicObject.Rotation = Matrix.CreateFromQuaternion(xWing.xWingRotation);

            
        }

        protected override void CleanUp(EngineStuff engine)
        {
            engine.RemoveComponent("SkyBox");
            base.CleanUp(engine);
        }

        void Colidiu(BEPUphysics.Collidables.MobileCollidables.EntityCollidable sender, BEPUphysics.Collidables.Collidable other, BEPUphysics.NarrowPhaseSystems.Pairs.CollidablePairHandler pair)
        {
            IObject send = BepuEntityObject.RecoverObjectFromEntity(sender.Entity);
            IObject obj = BepuEntityObject.RecoverObjectFromCollidable(other);

            ///Verifica se esta bola ja foi considerada
            ///Consider just the first collision
            //if (alreadProcessed.Contains(obj.GetId()))
            //    return;

            //alreadProcessed.Add(obj.GetId());

            ///se o objeto colidido for diferente do cenario 
            ///dont consider the island model (triangle meshes in general)
            if (obj.PhysicObject.PhysicObjectTypes != PhysicObjectTypes.TRIANGLEMESHOBJECT)
            {
                shouldDraw = true;

                ///Envia uma mensagem para o canal de comunicacao CUBO
                ///Send a message to the channel
                //Message m = new Message(send.GetId(), PrincipalConstants.InvalidId, "cubo", Priority.MEDIUM, -1, SenderType.OBJECT, null, "CHANGECOLOR");
                //MessageDeliver.SendMessage(m);

                /////Esta mensagem foi enviada sem Sender (Quem receber a mensagem nao sabera quem enviou)
                /////Envia uma mensagem para o "CUBO QUE VAI MUDAR DE COR" (lembre qoverue o id dele eh 77 !!)
                /////Send a message to the specific  id (first cube)
                //m = new Message(PrincipalConstants.InvalidId, 77, null, Priority.MEDIUM, -1, SenderType.OBJECT, null, "CHANGECOLOR");
                //MessageDeliver.SendMessage(m);
            }

            objNameTemp = obj.Name;
        }

        bool shouldDraw;
        string objNameTemp;

        private void ProcessKeyboard(GameTime gameTime)
        {
            float leftRightRot = 0;

            float turningSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
            turningSpeed *= 0.1f * gameSpeed;
            KeyboardState keys = Keyboard.GetState();
            if (keys.IsKeyDown(Keys.Right))
                leftRightRot -= turningSpeed;
            if (keys.IsKeyDown(Keys.Left))
                leftRightRot += turningSpeed;

            float upDownRot = 0;
            if (keys.IsKeyDown(Keys.Down))
                upDownRot -= turningSpeed;
            if (keys.IsKeyDown(Keys.Up))
                upDownRot += turningSpeed;

            Quaternion additionalRot = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), leftRightRot) *
                Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), upDownRot);

            xWing.xWingRotation *= additionalRot;

           
        }

        private void MoveForward(ref Vector3 position, Quaternion rotationQuat, float speed)
        {
            Vector3 addVector = Vector3.Transform(new Vector3(0, 0, 1f), rotationQuat);
            position += addVector * speed;
            //xWing.PhysicObject.Position = position;
            xWing.PhysicObject.ApplyImpulse(position, addVector * speed);
        }

       
    }
}
